package drds.binlog.binlog_event.event.unimportance;

import drds.binlog.binlog_event.LogByteBlock;
import drds.binlog.binlog_event.LogEvent;
import drds.binlog.binlog_event.event.FormatDescriptionLogEvent;
import drds.binlog.binlog_event.event.LogHeader;
import drds.binlog.common.Authors;
import drds.common.Author;
import lombok.Getter;
import lombok.Setter;

/**
 * Class representing an incident, an occurance out of the ordinary, that
 * happened on the master. The event is used to inform the slave that something
 * out of the ordinary happened on the master that might cause the database to
 * be in an inconsistent state.
 * <table id="IncidentFormat">
 * <caption>Incident event format</caption>
 * <tr>
 * <th>Symbol</th>
 * <th>Format</th>
 * <th>Description</th>
 * </tr>
 * <tr>
 * <td>INCIDENT</td>
 * <td align="right">2</td>
 * <td>Incident number as an unsigned integer</td>
 * </tr>
 * <tr>
 * <td>MSGLEN</td>
 * <td align="right">1</td>
 * <td>Message length as an unsigned integer</td>
 * </tr>
 * <tr>
 * <td>MESSAGE</td>
 * <td align="right">MSGLEN</td>
 * <td>The message, if present. Not null terminated.</td>
 * </tr>
 * </table>
 */
@Author(name = Authors.LI_YANG)
public final class IncidentLogEvent extends LogEvent
{

    public static final int incident_none = 0;

    /**
     * there are possibly lost events in the replication stream
     */
    public static final int incident_lost_events = 1;

    /**
     * shall be last event of the enumeration
     */
    public static final int incident_count = 2;

    @Setter
    @Getter
    private final int incident;
    @Setter
    @Getter
    private final String message;

    public IncidentLogEvent(LogHeader logHeader, LogByteBlock logByteBlock, FormatDescriptionLogEvent formatDescriptionLogEvent)
    {
        super(logHeader);

        final int commonHeaderLength = formatDescriptionLogEvent.commonHeaderLength;
        final int postHeaderLength = formatDescriptionLogEvent.postHeaderLengths[logHeader.logType - 1];

        logByteBlock.setIndexAsOriginIndexAndOffset(commonHeaderLength);
        final int incidentNumber = logByteBlock.getLittleEndian2UnsignedIntByIndex();
        if (incidentNumber >= incident_count || incidentNumber <= incident_none)
        {
            // If the incident is not recognized, this binlog event is
            // invalid. If we set incident_number to INCIDENT_NONE, the
            // invalidity will be detected by is_valid().
            incident = incident_none;
            message = null;
            return;
        }
        incident = incidentNumber;

        logByteBlock.setIndexAsOriginIndexAndOffset(commonHeaderLength + postHeaderLength);
        message = logByteBlock.getString();
    }

}
